# -*- coding: utf-8 -*-
"""
Redis客户端配置

提供Redis连接和基本操作：
- 连接管理
- 键值操作
- 过期时间设置
- 验证码存储专用方法
"""

import redis
import logging
from typing import Optional, Union
from .config import get_settings

logger = logging.getLogger(__name__)
settings = get_settings()


class RedisClient:
    """Redis客户端管理器"""
    
    def __init__(self):
        """初始化Redis连接"""
        self.redis_client: Optional[redis.Redis] = None
        self._connect()
    
    def _connect(self):
        """建立Redis连接"""
        try:
            # 从环境变量或配置文件获取Redis配置
            redis_url = getattr(settings, 'REDIS_URL', 'redis://localhost:6379/0')
            
            self.redis_client = redis.from_url(
                redis_url,
                decode_responses=True,  # 自动解码响应为字符串
                socket_connect_timeout=5,
                socket_timeout=5
            )
            
            # 测试连接
            self.redis_client.ping()
            logger.info("Redis连接成功")
            
        except Exception as e:
            logger.error(f"Redis连接失败: {e}")
            # 如果Redis连接失败，使用内存缓存作为备选方案
            self.redis_client = None
    
    def get(self, key: str) -> Optional[str]:
        """获取键值"""
        try:
            if self.redis_client:
                return self.redis_client.get(key)
            else:
                # 内存缓存备选方案
                return self._memory_cache.get(key)
        except Exception as e:
            logger.error(f"Redis GET操作失败 {key}: {e}")
            return None
    
    def set(self, key: str, value: Union[str, int], ex: Optional[int] = None) -> bool:
        """设置键值，可指定过期时间（秒）"""
        try:
            if self.redis_client:
                return self.redis_client.set(key, value, ex=ex)
            else:
                # 内存缓存备选方案
                self._memory_cache[key] = value
                if ex:
                    # 简单的内存过期处理（生产环境应使用更完善的方案）
                    import threading
                    import time
                    def expire_key():
                        time.sleep(ex)
                        self._memory_cache.pop(key, None)
                    threading.Thread(target=expire_key, daemon=True).start()
                return True
        except Exception as e:
            logger.error(f"Redis SET操作失败 {key}: {e}")
            return False
    
    def delete(self, key: str) -> bool:
        """删除键"""
        try:
            if self.redis_client:
                return bool(self.redis_client.delete(key))
            else:
                self._memory_cache.pop(key, None)
                return True
        except Exception as e:
            logger.error(f"Redis DELETE操作失败 {key}: {e}")
            return False
    
    def incr(self, key: str, amount: int = 1) -> Optional[int]:
        """递增计数器"""
        try:
            if self.redis_client:
                return self.redis_client.incr(key, amount)
            else:
                current = int(self._memory_cache.get(key, 0))
                new_value = current + amount
                self._memory_cache[key] = new_value
                return new_value
        except Exception as e:
            logger.error(f"Redis INCR操作失败 {key}: {e}")
            return None
    
    def expire(self, key: str, seconds: int) -> bool:
        """设置键的过期时间"""
        try:
            if self.redis_client:
                return self.redis_client.expire(key, seconds)
            return True  # 内存缓存暂不支持单独设置过期
        except Exception as e:
            logger.error(f"Redis EXPIRE操作失败 {key}: {e}")
            return False
    
    # 验证码专用方法
    def store_captcha(self, session_id: str, captcha_code: str, ttl: int = 300) -> bool:
        """存储验证码"""
        key = f"captcha:{session_id}"
        return self.set(key, captcha_code.upper(), ex=ttl)
    
    def verify_captcha(self, session_id: str, user_input: str) -> bool:
        """验证验证码"""
        key = f"captcha:{session_id}"
        stored_code = self.get(key)
        
        if not stored_code:
            logger.warning(f"验证码不存在或已过期: {session_id}")
            return False
        
        is_valid = stored_code.upper() == user_input.upper()
        
        if is_valid:
            # 验证成功后删除验证码
            self.delete(key)
            logger.info(f"验证码验证成功: {session_id}")
        else:
            logger.warning(f"验证码验证失败: {session_id}")
        
        return is_valid
    
    # 登录失败计数专用方法
    def increment_login_fails(self, username: str, ttl: int = 1800) -> int:
        """增加登录失败计数"""
        key = f"login_fails:{username}"
        count = self.incr(key)
        
        if count == 1:  # 第一次失败，设置过期时间
            self.expire(key, ttl)
        
        logger.info(f"用户 {username} 登录失败计数: {count}")
        return count
    
    def get_login_fails(self, username: str) -> int:
        """获取登录失败次数"""
        key = f"login_fails:{username}"
        count = self.get(key)
        return int(count) if count else 0
    
    def reset_login_fails(self, username: str) -> bool:
        """重置登录失败计数"""
        key = f"login_fails:{username}"
        success = self.delete(key)
        if success:
            logger.info(f"重置用户 {username} 登录失败计数")
        return success
    
    def is_captcha_required(self, username: str, threshold: int = 3) -> bool:
        """判断是否需要显示验证码"""
        fails = self.get_login_fails(username)
        return fails >= threshold
    
    # 内存缓存备选方案
    _memory_cache = {}
    
    def clear_memory_cache(self) -> bool:
        """清除内存缓存"""
        try:
            self._memory_cache.clear()
            logger.info("内存缓存已清除")
            return True
        except Exception as e:
            logger.error(f"清除内存缓存失败: {e}")
            return False


# 全局Redis客户端实例
redis_client = RedisClient()


# 便捷函数
def get_redis() -> RedisClient:
    """获取Redis客户端实例"""
    return redis_client